package net.lulihu.common_util.fastJson;

import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONException;
import lombok.extern.slf4j.Slf4j;
import net.lulihu.Assert;
import net.lulihu.ObjectKit.BeanKit;
import net.lulihu.ObjectKit.ClassKit;
import net.lulihu.ObjectKit.MapKit;
import net.lulihu.ObjectKit.ObjectKit;
import net.lulihu.functional.FieldValueProvider;
import net.lulihu.http.HttpServletRequestExpandFilter;
import net.lulihu.http.HttpServletRequestExpandWrapper;
import net.lulihu.http.RequestExpandWrapperUtil;
import org.springframework.boot.autoconfigure.condition.ConditionalOnClass;
import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean;
import org.springframework.boot.autoconfigure.condition.ConditionalOnWebApplication;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.core.MethodParameter;
import org.springframework.lang.NonNull;
import org.springframework.web.bind.support.WebDataBinderFactory;
import org.springframework.web.context.request.NativeWebRequest;
import org.springframework.web.method.support.HandlerMethodArgumentResolver;
import org.springframework.web.method.support.ModelAndViewContainer;
import org.springframework.web.servlet.config.annotation.WebMvcConfigurer;

import javax.servlet.http.HttpServletRequest;
import java.io.IOException;
import java.lang.reflect.Field;
import java.lang.reflect.ParameterizedType;
import java.lang.reflect.Type;
import java.util.Collection;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

/**
 * fastJson请求参数解析器配置
 */
@Slf4j
@Configuration
@ConditionalOnClass(com.alibaba.fastjson.JSON.class)
@ConditionalOnMissingBean(FastJsonHttpMessageResolverConfig.FastJsonHandlerMethodArgumentResolver.class)
@ConditionalOnWebApplication
public class FastJsonHttpMessageResolverConfig {

    public FastJsonHttpMessageResolverConfig() {
        if (log.isInfoEnabled())
            log.info("==== 加载FastJsonHttpMessageResolver组件 ====");
    }

    @Bean
    public FastJsonWebMvcConfigurer fastJsonWebMvcConfigurer() {
        return new FastJsonWebMvcConfigurer();
    }

    /**
     * HttpServletRequest拓展对象过滤器
     */
    @Bean
    public HttpServletRequestExpandFilter requestBodyReaderFilter() {
        log.info("==== 加载HttpServletRequest拓展对象过滤器 ====");
        return new HttpServletRequestExpandFilter();
    }

    /**
     * FastJsonWebMvcConfigurer
     */
    public static class FastJsonWebMvcConfigurer implements WebMvcConfigurer {

        /**
         * 注册请求参数解析器
         * <p>
         * 使用fastJson来解析请求参数
         */
        @Override
        public void addArgumentResolvers(List<HandlerMethodArgumentResolver> argumentResolvers) {
            argumentResolvers.add(new FastJsonHandlerMethodArgumentResolver());
        }
    }

    /**
     * FastJsonHandlerMethodArgumentResolver
     */
    public static class FastJsonHandlerMethodArgumentResolver implements HandlerMethodArgumentResolver {
        /**
         * 只有使用 @FastJson 注解的参数才进行参数解析
         * <p>
         * fastJson注解 只支持JavaBean对象
         */
        @Override
        public boolean supportsParameter(@NonNull MethodParameter parameter) {
            Class<?> parameterType = parameter.getParameterType();
            return parameter.hasParameterAnnotation(FastJson.class)
                    && (BeanKit.isBean(parameterType) || ClassKit.isAssignable(List.class, parameterType));
        }

        @Override
        public Object resolveArgument(@NonNull MethodParameter parameter, ModelAndViewContainer mavContainer,
                                      @NonNull NativeWebRequest webRequest, WebDataBinderFactory binderFactory) {
            HttpServletRequestExpandWrapper servletRequest = webRequest.getNativeRequest(HttpServletRequestExpandWrapper.class);
            Assert.notNull(servletRequest, "HttpServletRequestExpandWrapper 对象不存在，加载异常...");

            Class<?> parameterType = parameter.getParameterType();
            // bean对象
            if (BeanKit.isBean(parameterType)) {
                Map<String, Object> requestParameters = RequestExpandWrapperUtil.requestParams(servletRequest, new HashMap<>());
                if (MapKit.isEmpty(requestParameters))
                    return ClassKit.newInstanceConstructorsDefaultValue(parameterType);

                try {
                    String json = JSON.toJSONString(requestParameters);
                    return JSON.parseObject(json, parameterType);
                    // 兼容模式
                } catch (JSONException e) {
                    return BeanKit.fillBeanField(ClassKit.newInstance(parameterType), (FieldValueProvider) (field) -> {
                        Object value = requestParameters.get(field.getName());
                        if (ObjectKit.hasEmpty(value)) return null;
                        // 不匹配时
                        if (!value.getClass().equals(field.getType()))
                            return distribute(value, field);
                        return value;
                    });
                }

                //集合对象
            } else if (ClassKit.isAssignable(List.class, parameterType)) {
                Type genericType = parameter.getParameter().getParameterizedType();
                if (genericType instanceof ParameterizedType) {
                    ParameterizedType pt = (ParameterizedType) genericType;
                    return RequestExpandWrapperUtil.requestParams(servletRequest, (Class<?>) pt.getActualTypeArguments()[0]);
                }
            }
            throw new IllegalArgumentException("不支持的封装类型...");
        }

        /**
         * 处理数据分发
         *
         * @param value 值
         * @param field 字段属性
         */
        private Object distribute(Object value, Field field) {
            String val = value instanceof String ? (String) value : JSON.toJSONString(value);
            Class<?> clazz = field.getType();
            // 处理集合
            if (Collection.class.isAssignableFrom(clazz)) {
                return processCollection(val, field);
            }
            return JSON.parseObject(val, clazz);
        }

        /**
         * 处理集合
         *
         * @param value 值
         * @param field 字段类型
         * @return 序列化之后的值
         */
        private Object processCollection(String value, Field field) {
            Type genericType = field.getGenericType();
            // 如果是泛型参数的类型
            if (genericType instanceof ParameterizedType) {
                ParameterizedType pt = (ParameterizedType) genericType;
                return JSON.parseArray(value, (Class<?>) pt.getActualTypeArguments()[0]);
            }
            return null;
        }
    }
}
